﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Diagnostics;

namespace LowLevelGraphics.ColorSpaces
{
    /// <summary>
    /// YIQ Channel
    /// </summary>
    public enum YIQChannel
    {
        /// <summary>
        /// 
        /// </summary>
        Y = 0,
        /// <summary>
        /// 
        /// </summary>
        I = 1,
        /// <summary>
        /// 
        /// </summary>
        Q = 2
    }

    /// <summary>
    /// Class to convert YIQ and back
    /// </summary>
    [DebuggerDisplay("Y: {m_Y}, I: {m_I}, Q: {m_Q}")]
    public class YIQ : AbstractColorSpace
    {
        protected float m_Y = 0.0f;
        protected float m_I = 0.0f;
        protected float m_Q = 0.0f;

        /// <summary>
        /// Primary constructor
        /// </summary>
        /// <param name="_color"></param>
        public YIQ(Color _color)
            : base(_color)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="YIQ"/> class.
        /// </summary>
        /// <param name="_Y">The _ Y.</param>
        /// <param name="_I">The _ I.</param>
        /// <param name="_Q">The _ Q.</param>
        public YIQ(float _Y, float _I, float _Q)
        {
            m_Y = _Y;
            m_I = _I;
            m_Q = _Q;
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_yiq"></param>
        internal YIQ(YIQ _yiq)
        {
            this.m_Color = _yiq.m_Color;
            this.m_Y = _yiq.m_Y;
            this.m_I = _yiq.m_I;
            this.m_Q = _yiq.m_Q;
        }

        /// <summary>
        /// Performs an explicit conversion from <see cref="System.Drawing.Color"/> to <see cref="LowLevelGraphics.ColorSpaces.YIQ"/>.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns>The result of the conversion.</returns>
        public static explicit operator YIQ(Color _color)
        {
            return new YIQ(_color);
        }

        /// <summary>
        /// Gets or sets Y
        /// </summary>
        public float Y
        {
            get { return m_Y; }
            set { m_Y = value; }
        }

        /// <summary>
        /// Gets or sets I
        /// </summary>
        public float I
        {
            get { return m_I; }
            set { m_I = value; }
        }

        /// <summary>
        /// Gets or sets Q
        /// </summary>
        public float Q
        {
            get { return m_Q; }
            set { m_Q = value; }
        }

        /// <summary>
        /// Converts color into this color space
        /// </summary>
        protected override void CalcValues()
        {
            m_Y = 0.299f * m_Color.R + 0.587f * m_Color.G + 0.114f * m_Color.B;
            m_I = 0.596f * m_Color.R - 0.274f * m_Color.G - 0.322f * m_Color.B;
            m_Q = 0.212f * m_Color.R - 0.523f * m_Color.G + 0.311f * m_Color.B;
        }

        /// <summary>
        /// retransform color back to RGB
        /// </summary>
        /// <returns></returns>
        public override Color ToColor()
        {
            float fR = 1.0f * m_Y + 0.956f * m_I + 0.621f * m_Q;
            float fG = 1.0f * m_Y - 0.272f * m_I - 0.647f * m_Q;
            float fB = 1.0f * m_Y - 1.105f * m_I + 1.702f * m_Q;

            if (fR < 0) fR = 0; if (fR > 255) fR = 255;
            if (fG < 0) fG = 0; if (fG > 255) fG = 255;
            if (fB < 0) fB = 0; if (fB > 255) fB = 255;
            return Color.FromArgb((int)fR, (int)fG, (int)fB);
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("Color Y = {0}, I = {1}, Q = {2}", m_Y, m_I, m_Q);
        }

        /// <summary>
        /// Gets the values.
        /// </summary>
        /// <returns></returns>
        public override object[] GetValues()
        {
            return new object[] { m_Y, m_I, m_Q };
        }

        /// <summary>
        /// Sets the values.
        /// </summary>
        /// <param name="_aObject">The _a object.</param>
        public override void SetValues(object[] _aObject)
        {
            this.m_Y = (float)_aObject[0];
            this.m_I = (float)_aObject[1];
            this.m_Q = (float)_aObject[2];
        }

        /// <summary>
        /// Use this to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new YIQ(this);
        }
    }
}
